<?php
/**
 * DnToolkit
 * 
 * @author Dvaknheo
 * @category Project
 * @copyright Copyright(c) 2012 
 * @version $Id$
 */

// fixeme 受 amfphp 类库的限制，本类没有 设定成同时加载 amfphp 和 json 和 xml 协议  ，但是调整后可以做到.
// DnGateway 和 DnDiscoveryService  一起合用。
// DnGateway fix 了 amfphp 中 切换目录到 services 的 bug;
if (!defined('AMFPHP_BASE')) {
	require_once (DN_APPPATH . 'amfphp/core/amf/app/Gateway.php');
	//require_once(AMFPHP_BASE . "shared/util/MessageBody.php");
}
class DnGateway extends Gateway {
	protected $browserPassword;
	protected $serviceClasses=array();
	protected $servicePathes=array();
	protected $hook_class_create=null;
	public $is_class_self_create=true;
	
	//////////////////////////////////
	public static function Self($obj = null) {
		$classname = __CLASS__;
		$mustbe_childclass = false;
		$key = 'Dvaknheo_' . $classname;
		if ($obj) {
			if ($mustbe_childclass && !is_a($obj, $classname)) {
				$GLOBALS[$key] = $GLOBALS[$key] ? $GLOBALS[$key] : new $classname ($obj);
			} else {
				$GLOBALS[$key] = $obj;
			}
		} else
			if (!isset ($GLOBALS[$key])) {
				$GLOBALS[$key] = new $classname ();
			}
		return $GLOBALS[$key];
	}
	//////////////////////////////////
	public function __construct() {
		global $amfphp;
		$amfphp['startTime'] =microtime(true);
		
		if(!defined('DN_LIB_PATH')){
			define('DN_LIB_PATH',realpath(dirname(__FILE__)).'/');
		}
		parent :: __construct();
		$str=$_SERVER['PATH_INFO'];
		if($str{0}=='/'){
			$this->is_json=true;
		}
		
		
		$this->setClassPath(DN_LIB_PATH);
		
		
		//Set where class mappings are loaded from (ie: for VOs)
		//$voPath defined in globals.php
		//$gateway->setClassMappingsPath($voPath); 

		//Read above large note for explanation of charset handling
		//The main contributor (Patrick Mineault) is French, 
		
		//$gateway->setCharsetHandler("utf8_decode", "ISO-8859-1", "ISO-8859-1");

		//Error types that will be rooted to the NetConnection debugger
		//$gateway->setErrorHandling(E_ALL ^ E_NOTICE);
		//$gateway->setCharsetHandler("utf8_decode", "UTF8", "UTF8");

		if (!$_SESSION['DN_ALLOW_AMF']) {
			//Disable profiling, remote tracing, and service browser
			$this->disableAllDebug();
		}
	}
	protected function disableAllDebug()
	{
		$this->disableDebug();
		// Keep the Flash/Flex IDE player from connecting to the gateway.
		// Used for security to stop remote connections. 
		$this->disableStandalonePlayer();
		$this->enableGzipCompression(25 * 1024);
	}
	protected $is_json=false;
	protected function showErrorPage() {
		$has_model = function_exists("amf_decode");
		$has_loadmodel = $GLOBALS['amfphp']['native'];
		echo<<<eot
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<p>欢迎访问Dvaknheo AMF 模块</p>
eot;
		if ($has_model) {
			echo<<<eot
<p>AMF C Extension 已经装载
eot;
		}
		if ($has_loadmodel) {
			echo "[启用]";
		} else {
			echo " [未启用]";
		}
		echo<<<eot
</p>
	TODO 开启  AMFPHP +管理页面
eot;
		echo date(DATE_W3C);
	}
	
	public function setDefaultServicePath($path)
	{
	}
	public function addServicePath($path,$package=NULL)
	{
		if(NULL===$package){
			$package=basename($path);
		}
		$this->servicePathes[$package]=$path;
	}
	public function addServiceClass($className,$package=NULL)
	{
		$this->serviceClasses[$className]=$package;
	}
	public function setBrowserPassword($password)
	{
		$this->browserPassword=$password;
	}
	public function getBrowserPassword()
	{
		return $this->browserPassword;
	}
	
	public function setCreateClassHook($callback=null)
	{
		$this->hook_class_create=$callback;
	}
	public function setClassSelfCreate($flag=true)
	{
		$this->is_class_self_create=$flag;
	}
	
	public function createClass($className)
	{
		$construct=false;
		if(is_callable($this->hook_class_create)){
				$construct = call_user_func($this->hook_class_create,$className);
		}
		if(false===$construct){
			if($this->is_class_self_create){
				////
				$class = new ReflectionClass($className);
				$methods = $class->getMethods();
				$flag=false;
				foreach ($methods as $reflectionMethod) {
					if ($reflectionMethod->name == 'DnAmfClassSelfCreate' && $reflectionMethod->isStatic()) {
						$flag=true;
						break;
					}
				}
				if($flag){
					$construct = call_user_func(array($className,'DnAmfClassSelfCreate'),$className);
				}else{
					$construct = new $className($className);
				}
				////
			}else{
				$construct = new $className($className);
			}
		}
		return $construct;
	}
	/////////////////////////////////////////////////////
	public function getServices()
	{
		//label,data='dir',chidren=>array,open=>false;
		$ret=array();
		//$gateway->addServicePath(DN_LIB_PATH);
		$servicePathes=$this->servicePathes;
		$servicePathes=array_merge(array('DnToolkit'=>DN_LIB_PATH),$servicePathes);
		foreach($servicePathes as $package=>$path){
			$services=array();
			$files=scandir($path);
			foreach($files as $file){
				$flag=preg_match('/([^\.]+)(\.class)\.(php)/A',$file,$m);
				$className=$m[1];
				if(!$flag){continue;}
				$services[] = array (
					'label'=>$className,
					'data'=>$package.'/',
				);
			}
			$ret[]=array (
				'label' => $package,
				'children' => $services,
				'open' => true,
			);
		}
		foreach($this->serviceClasses as $className=>$mypackage){
			$ret[]=array (
				'label' => $className,
				'data' => $mypackage.'/',
			);
		}
		
		return $ret;
	}
	
	
	function json_service()
	{
		require_once(AMFPHP_BASE . "shared/util/MessageBody.php");
		
		$this->actions=array();
		$this->actions['deserialization'] = 'json_deserializationAction';
		$this->actions['classLoader'] = 'Dn_classLoaderAction';
		$this->actions['security'] = 'Dn_securityAction';
		$this->actions['exec'] = 'json_executionAction';
		$this->actions['serialization'] = 'json_serializationAction';
	
		//Process the arguments
		$body = $this->createJsonBody();
		foreach($this->actions as $key => $action)
		{
			$result = $action($body); //   invoke the first filter in the chain
			if($result === false)
			{
				//Go straight to serialization actions
				$serAction = $this->actions['serialization'];
				$serAction($body);
				break;
			}
		}
		echo $body->getResults();
	}
	public function createJsonBody()
	{
		$GLOBALS['amfphp']['encoding'] = 'json';
		$body = & new MessageBody();
		
		$uri = dn__setUri();
		$elements = explode('/gateway.php', $uri);
		
		if(strlen($elements[1]) == 0)
		{
			echo("The JSON gateway is installed correctly. Call like this: json.php/MyClazz.myMethod/arg1/arg2");
			exit();
		}
		$args = substr($elements[1], 1);
		$rawArgs = explode('/', $args);
		
		if(isset($GLOBALS['HTTP_RAW_POST_DATA']))
		{
			$rawArgs[] = $GLOBALS['HTTP_RAW_POST_DATA'];
		}
		$body->setValue($rawArgs);
		return $body;
	}
	
		
	public function service() {
		if($this->is_json){
			return $this->json_service();
		}
		if (isset ($GLOBALS["HTTP_RAW_POST_DATA"]) && $GLOBALS["HTTP_RAW_POST_DATA"] != "") {
			if ($this->is_allow_amf) {
				ini_set('display_errors', true);
			}
			if (!defined('DN_IN_AMF')) {
				define('DN_IN_AMF', true);
			}
			$ret = parent :: service();

			return $ret;
		} else {
			header("cache-control: no-cache, must-revalidate");
			$this->showErrorPage();
		}
	}
	
	
	//////////////////////////////////////////////////////////////////////////
	public function registerActionChain() {
		$this->actions=array();
		$this->actions['adapter'] = 'Dn_adapterAction'; 
		//把 amfphp 的 DiscoveryService 类映射成 DnDiscoveryService 类和文件
		$this->actions['class'] = 'Dn_classLoaderAction'; 
		$this->actions['security'] = 'Dn_securityAction';
		$this->actions['exec'] = 'Dn_executionAction';
		//$this->actions['exec'] = 'Dn_executionAction';
		
		return;
	}

	public function adapterAction(&$amfbody)
	{
		$ret = adapterAction($amfbody);
		
		if ('DiscoveryService' == $amfbody->className) {
			$amfbody->classPath = DN_LIB_PATH . 'DnDiscoveryService.class.php';
			$amfbody->className = 'DnDiscoveryService';
		}
		return $ret;
	}
	public function securityAction(& $amfbody) 
	{
		if ($amfbody->noExec) {
			return true;
		}
		$classConstruct = & $amfbody->getClassConstruct();
		$methodName = $amfbody->methodName;
		$className = $amfbody->className;

		$is_extmethod = method_exists($classConstruct, 'dnAmfExtMethod');
		if (!method_exists($classConstruct, $methodName)) { // check to see if the method exists
			if (!$is_extmethod) {
				$ex = new MessageException(E_USER_ERROR, "The method  {" . $methodName . "} does not exist in class {" . get_class($classConstruct).'|'.$className . "}.", __FILE__, __LINE__, "AMFPHP_INEXISTANT_METHOD");
				MessageException :: throwException($amfbody, $ex);
				return false;
			}
		}
		//Check if method is private (PHP4)
		if (strpos($methodName, '_') === 0) { // check to see if the method exists
			$ex = new MessageException(E_USER_ERROR, "The method  {" . $methodName . "} starts with an underscore and is therefore considered private, so it cannot be remotely called.", __FILE__, __LINE__, "AMFPHP_PRIVATE_METHOD");
			MessageException :: throwException($amfbody, $ex);
			return false;
		}

		//Check to see if method is private or protected (PHP5)
		if (class_exists('ReflectionMethod') && !$is_extmethod) {
			$method = new ReflectionMethod($className, $methodName);
			if (!$method->isPublic()) {
				$ex = new MessageException(E_USER_ERROR, "The method  {" . $methodName . "} in {" . $className . "} is not public and therefore cannot be called.", __FILE__, __LINE__, "AMFPHP_PRIVATE_METHOD");
				MessageException :: throwException($amfbody, $ex);
				return false;
			}
		}

		$classConstruct = & $amfbody->getClassConstruct();
		$methodName = $amfbody->methodName;
		$className = $amfbody->className;

		if (!isset ($_SESSION['DN_ALLOW_AMF']) && !method_exists($classConstruct, "dnAmfAllowRemoteCall")) {
			$ex = new MessageException(E_USER_ERROR, "You  Need A Method to Allow remotecall dnAmfAllowRemoteCall,see the file and the line" . $className . " class", __FILE__, __LINE__, "AMFPHP_AUTHENTICATE_ERROR");
			MessageException :: throwException($amfbody, $ex);
			return false;
		} else if (method_exists($classConstruct, "beforeFilter")) {
			//Pass throught the executive
			$allow = Executive :: doMethodCall($amfbody, $classConstruct, 'beforeFilter', array (
				$methodName
			));
			if ($allow === '__amfphp_error' || $allow === false) {
				$ex = new MessageException(E_USER_ERROR, "Method access blocked by beforeFilter in " . $className . " class", __FILE__, __LINE__, "AMFPHP_AUTHENTICATE_ERROR");
				MessageException :: throwException($amfbody, $ex);
				return false;
			}
		}
		return true;
	}
	public function classLoaderAction(& $amfbody)
	{
		if ($amfbody->noExec) {
			return true;
		}
		/*
		$cwd = getcwd();
		// change to the gateway.php script directory
		// now change to the directory of the classpath.  Possible relative to gateway.php
		$dirname = dirname($amfbody->classPath);
		if (!is_dir($dirname)) {
			$ex = new MessageException(E_USER_ERROR, "The classpath folder {" . $amfbody->classPath . "} does not exist. You probably misplaced your service.", __FILE__, __LINE__, "AMFPHP_CLASSPATH_NOT_FOUND");
			MessageException :: throwException($amfbody, $ex);
			return false;
		}
		chdir($dirname);
		$fileExists = @ file_exists($amfbody->className.'.class.php'); // see if the file exists
		
		if (!$fileExists) {
			$ex = new MessageException(E_USER_ERROR, "The class {" . $amfbody->className . "} could not be found under the class path {" . $amfbody->classPath . "}", __FILE__, __LINE__, "AMFPHP_FILE_NOT_FOUND");
			MessageException :: throwException($amfbody, $ex);
			return false;
		}

		global $amfphp;
		$time = microtime_float();
		$fileIncluded = Executive :: includeClass($amfbody, $amfbody->className.'.class.php');
		$amfphp['includeTime'] += microtime_float() - $time;

		if (!$fileIncluded) {
			$ex = new MessageException(E_USER_ERROR, "The class file {" . $amfbody->className . "} exists but could not be included. The file may have syntax errors, or includes at the top of the file cannot be resolved.", __FILE__, __LINE__, "AMFPHP_FILE_NOT_INCLUDED");
			MessageException :: throwException($amfbody, $ex);
			return false;
		}

		if (!class_exists($amfbody->className)) { // Just make sure the class name is the same as the file name

			$ex = new MessageException(E_USER_ERROR, "The file {" . $amfbody->className . ".php} exists and was included correctly but a class by that name could not be found in that file. Perhaps the class is misnamed.", __FILE__, __LINE__, "AMFPHP_CLASS_NOT_FOUND");
			MessageException :: throwException($amfbody, $ex);
			return false;
		}

		//Let executive handle building the class
		//The executive can handle making exceptions and all that, that's why
		chdir($cwd);
		*/
		//$amfphp['includeTime'] += microtime_float() - $time;
		$classConstruct = $this->buildClass($amfbody, $amfbody->className);
		if ($classConstruct !== '__amfphp_error') {
			$amfbody->setClassConstruct($classConstruct);
		} else {
			return false;
		}
		return true;
	}
	

	protected function buildClass(&$bodyObj, $className)
	{
		global $amfphp;
		if(isset($amfphp['classInstances'][$className]))
		{
			return $amfphp['classInstances'][$className];
		}
		
		try
		{
			$this->createClass($className);
			if(is_callable($this->hook_class_create)){
				$construct = call_user_func($this->hook_class_create,$className);
				if(false===$construct){
					$construct = $this->createClass($className);
				}
			}else{
				$construct = $this->createClass($className);
			}		
			$amfphp['classInstances'][$className] = & $construct;
		}
		catch(Exception $fault)
		{
			//When constructing a class, getLine and getFile don't refer to the appropriate thing,
			//hence this hack
			$ex = new MessageException(E_USER_ERROR, $fault->getMessage(), $bodyObj->classPath, 'Undetermined line  in constructor', 'AMFPHP_BUILD_ERROR');
			MessageException::throwException($bodyObj, $ex);
			$construct = '__amfphp_error';
		}
		
		return $construct;
	}
	
}
function dn__setUri() {
	if (__env('HTTP_X_REWRITE_URL')) {
		$uri = __env('HTTP_X_REWRITE_URL');
	} elseif(__env('REQUEST_URI')) {
		$uri = __env('REQUEST_URI');
	} else {
		if (__env('argv')) {
			$uri = __env('argv');

			if (defined('SERVER_IIS')) {
				$uri = BASE_URL . $uri[0];
			} else {
				$uri = __env('PHP_SELF') . '/' . $uri[0];
			}
		} else {
			$uri = __env('PHP_SELF') . '/' . __env('QUERY_STRING');
		}
	}
	return $uri;
}
function __env($key) {
	if (isset($_SERVER[$key])) {
		return $_SERVER[$key];
	} elseif (isset($_ENV[$key])) {
		return $_ENV[$key];
	} elseif (getenv($key) !== false) {
		return getenv($key);
	}

	if ($key == 'DOCUMENT_ROOT') {
		$offset=0;
		if (!strpos(__env('SCRIPT_NAME'), '.php')) {
			$offset = 4;
		}
		return substr(__env('SCRIPT_FILENAME'), 0, strlen(__env('SCRIPT_FILENAME')) - (strlen(__env('SCRIPT_NAME')) + $offset));
	}
	if ($key == 'PHP_SELF') {
		return r(__env('DOCUMENT_ROOT'), '', __env('SCRIPT_FILENAME'));
	}
	return null;
}
function Dn_adapterAction(& $amfbody) {
	return DnGateway::Self()->adapterAction(&$amfbody);
}


function Dn_securityAction(& $amfbody) {
	return DnGateway::Self()->securityAction(&$amfbody);
}

function Dn_classLoaderAction(& $amfbody) {
	return DnGateway::Self()->classLoaderAction(&$amfbody);
}

/**
 * ExecutionAction executes the required methods
 */
function Dn_executionAction (&$amfbody) 
{
	
	$specialHandling = $amfbody->getSpecialHandling();

	if (!$amfbody->isSpecialHandling() || $amfbody->isSpecialHandling(array('describeService', 'pageFetch', 'RemotingMessage')))
	{
		$construct = &$amfbody->getClassConstruct();
		$method = $amfbody->methodName;
		$args = $amfbody->getValue();
		
		if($specialHandling == 'describeService')
		{               
			include_once(AMFPHP_BASE . "util/DescribeService.php");
			$ds = new DescribeService();
			$results = $ds->describe($construct, $amfbody->className);
		}
		else if($specialHandling == 'pageFetch')
		{
			$args[count($args) - 2] = $args[count($args) - 2] - 1;
			
			$dataset = Executive::doMethodCall($amfbody, $construct, $method, $args);
			$results = array("cursor" => $args[count($args) - 2] + 1,
							 "data" => $dataset);
			$amfbody->setMetadata('type', '__DYNAMIC_PAGE__');
		}
		else
		{
			/*
			if(isset($construct->methodTable[$method]['pagesize']))
			{
				//Check if counting method was overriden
				if(isset($construct->methodTable[$method]['countMethod']))
				{
					$counter = $construct->methodTable[$method]['countMethod'];
				}
				else
				{
					$counter = $method . '_count';
				}
				
				$dataset = Executive::doMethodCall($amfbody, $construct, $method, $args); // do the magic
				$count = Executive::doMethodCall($amfbody, $construct, $counter, $args);
				
				//Include the wrapper
				$results = array('class' => $amfbody->uriClassPath, 
								 'method' => $amfbody->methodName, 
								 'count' => $count, 
								 "args" => $args, 
								 "data" => $dataset);
				$amfbody->setMetadata('type', '__DYNAMIC_PAGEABLE_RESULTSET__');
				$amfbody->setMetadata('pagesize', $construct->methodTable[$method]['pagesize']);
				*/
			//}
			//else
			//{
				//The usual
				$time = microtime_float();
				$results = Executive::doMethodCall($amfbody, $construct, $method, $args); // do the magic
				global $amfphp;
				$amfphp['callTime'] += microtime_float() - $time;
			//}
		}

		if($results !== '__amfphp_error')
		{
			if($specialHandling == 'RemotingMessage')
			{
				
				$wrapper = new AcknowledgeMessage($amfbody->getMetadata("messageId"), 
												  $amfbody->getMetadata("clientId"));
				$wrapper->body = $results;
				$amfbody->setResults($wrapper);
			}
			else
			{
				$amfbody->setResults($results);
			}
			
			$amfbody->responseURI = $amfbody->responseIndex . "/onResult";  
		}
		return false;
	}
	elseif($specialHandling == 'Ping')
	{
		$wrapper = new AcknowledgeMessage($amfbody->getMetadata("messageId"), 
										  $amfbody->getMetadata("clientId"));
		$amfbody->setResults($wrapper);
		$amfbody->responseURI = $amfbody->responseIndex . "/onResult";
	}
	else if($specialHandling == 'pageRelease')
	{
		//Ignore PageAbleResult.release
		$amfbody->setResults(true);
		$amfbody->setMetaData('type', 'boolean');
		$amfbody->responseURI = $amfbody->responseIndex . "/onResult";
		return false;
	}
	return true;
}


//// 以下方法尚未使用，尚未修改

function json_deserializationAction(& $body) {
	$args = $body->getValue();
	$target = $args[0];

	$baseClassPath = $GLOBALS['amfphp']['classPath'];

	$lpos = strrpos($target, '.');

	$methodname = substr($target, $lpos +1);
	$trunced = substr($target, 0, $lpos);
	$lpos = strrpos($trunced, ".");
	if ($lpos === false) {
		$classname = $trunced;
		$uriclasspath = $trunced . ".php";
		$classpath = $baseClassPath . $trunced . ".php";
	} else {
		$classname = substr($trunced, $lpos +1);
		$classpath = $baseClassPath . str_replace(".", "/", $trunced) . ".php"; // removed to strip the basecp out of the equation here
		$uriclasspath = str_replace(".", "/", $trunced) . ".php"; // removed to strip the basecp out of the equation here
	}
	$body->methodName = $methodname;
	$body->className = $classname;
	$body->classPath = $classpath;
	$body->uriClassPath = $uriclasspath;

	//Now deserialize the arguments
	array_shift($args);

	$actualArgs = array ();

	foreach ($args as $key => $value) {
		//Look at the value to see if it is JSON-encoded
		$value = urldecode($value);
		if ($value != "") {
			if ($value[0] != '[' && $value[0] != '{' && $value != "null" && $value != "false" && $value != "true") {
				//check to see if it is a number
				$char1 = ord($value[0]);
				if ($char1 >= 0x30 && $char1 <= 0x39) {
					//Then this is a number
					$value = json_decode($value, true);
				} //Else leave value as is
			} else {
				$value = json_decode($value, true);
			}
		}
		$actualArgs[] = $value;
	}

	$body->setValue($actualArgs);
}

function json_executionAction(& $body) {
	$classConstruct = & $body->getClassConstruct();
	$methodName = $body->methodName;
	$args = $body->getValue();

	//$output = Executive::doMethodCall($body, $classConstruct, $methodName, $args);
	$output = call_user_func_array(array (
		Executive,
		doMethodCall
	), array (
		$body,
		& $classConstruct,
		$methodName,
		$args
	));
	
	if ($output !== "__amfphp_error") {
		$body->setResults($output);
	}
}

function json_serializationAction(& $body) {
	//Take the raw response
	$rawResponse = & $body->getResults();

	adapterMap($rawResponse);

	//Now serialize it
	$encodedResponse = json_encode($rawResponse);

	if (count(NetDebug :: getTraceStack()) > 0) {
		$trace = "/*" . implode("\n", NetDebug :: getTraceStack()) . "*/";
		$encodedResponse = $trace . "\n" . $encodedResponse;
	}
	
	$body->setResults($encodedResponse);
}
function xml_deserializationAction(& $body) {
	$data = $body->getValue();

	//Get the method that is being called
	$description = xmlrpc_parse_method_descriptions($data);
	$target = $description['methodName'];

	$baseClassPath = $GLOBALS['amfphp']['classPath'];

	$lpos = strrpos($target, '.');

	$methodname = substr($target, $lpos +1);
	$trunced = substr($target, 0, $lpos);
	$lpos = strrpos($trunced, ".");
	if ($lpos === false) {
		$classname = $trunced;
		$uriclasspath = $trunced . ".php";
		$classpath = $baseClassPath . $trunced . ".php";
	} else {
		$classname = substr($trunced, $lpos +1);
		$classpath = $baseClassPath . str_replace(".", "/", $trunced) . ".php"; // removed to strip the basecp out of the equation here
		$uriclasspath = str_replace(".", "/", $trunced) . ".php"; // removed to strip the basecp out of the equation here
	}

	$body->methodName = $methodname;
	$body->className = $classname;
	$body->classPath = $classpath;
	$body->uriClassPath = $uriclasspath;
	$body->packageClassMethodName = $description['methodName'];
}

function xml_executionAction(& $body) {
	$classConstruct = $body->getClassConstruct();
	$methodName = $body->methodName;
	$className = $body->className;

	$xmlrpc_server = xmlrpc_server_create();

	$lambdaFunc = 'return adapterMap(call_user_func_array (array(&$userData[0], $userData[1]), $args));';
	$func = create_function('$a,$args,$userData', $lambdaFunc);

	xmlrpc_server_register_method($xmlrpc_server, $body->packageClassMethodName, $func);

	$request_xml = $body->getValue();
	$args = array (
		$xmlrpc_server,
		$request_xml,
		array (
			& $classConstruct,
			$methodName
		)
	);
	$nullObj = NULL;
	$response = Executive :: doMethodCall($body, $nullObj, 'xmlrpc_server_call_method', $args);
	//$response = xmlrpc_server_call_method();

	if ($response !== "__amfphp_error") {
		$body->setResults($response);
	} else {
		return false;
	}
}

/**
 * Debug action
 */
function xml_debugAction(& $body) {
	if (count(NetDebug :: getTraceStack()) != 0) {
		$previousResults = $body->getResults();
		$debugInfo = NetDebug :: getTraceStack();
		$debugString = "<!-- " . implode("\n", $debugInfo) . "-->";
		$body->setResults($debugString . "\n" . $previousResults);
	}
}

/**
 * This won't ever be called unless there is an error
 */
function xml_serializationAction(& $body) {
	$request_xml = $body->getValue();
	$toSerialize = $body->getResults();

	$lambdaFunc = 'return $userData;';
	$func = create_function('$a,$b,$userData', $lambdaFunc);

	$xmlrpc_server = xmlrpc_server_create();

	$request_xml = $body->getValue();

	xmlrpc_server_register_method($xmlrpc_server, $body->packageClassMethodName, $func);

	$response = xmlrpc_server_call_method($xmlrpc_server, $request_xml, $toSerialize);

	$body->setResults($response);
}